package com.cavy.platform.server.domain.job;

import com.cavy.platform.server.BeansProvider;
import com.cavy.platform.server.domain.*;
import com.cavy.platform.server.repository.JobRepository;
import com.cavy.platform.server.service.AgentSessionService;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.util.*;
import java.util.concurrent.TimeoutException;

import static java.util.Calendar.SECOND;

@EqualsAndHashCode(callSuper = true)
@Data
@Slf4j
public class PendingJob extends AbstractJobAction {
    protected Date pendingTimeout;
    private JobConfig jobConfig;

    public PendingJob() {
    }

    public PendingJob(Job job, JobConfig jobConfig) {
        super(job);
        this.jobConfig = jobConfig;
        Calendar instance = Calendar.getInstance();
        instance.setTime(job.getCreateTime());
        instance.add(SECOND, jobConfig.getPendingTimeOut());
        this.setPendingTimeout(instance.getTime());
    }

    public JobAction dispatch() throws UnknownOnlineAgentException, IOException, UnAvailableAgentException {
        JobAction target = this;
        try {
            checkPendingTimeout();
            AgentOnline agent = selectAgent();
            Agent info = agent.getInfo();
            setJobRunningTimeOut();
            agent.sendJob(job);
            target = new RunningJob(job, info);
            log.debug("job:{}调度完成", job);
            return target;
        } catch (TimeoutException e) {
            log.warn("调度job({},{},{},{})失败,job超时", job.workspaceName, job.projectName, job.pipelineName, job.number);
            target = new TimeoutErrorJob(job);
            return target;
        } finally {
            Objects.requireNonNull(BeansProvider.getBean(JobRepository.class)).save(target);
            sendJob();
        }
    }

    private void setJobRunningTimeOut() {
        Calendar instance = Calendar.getInstance();
        instance.add(SECOND, jobConfig.getRunningTimeOut());
        job.runningTimeOut = instance.getTime();
    }

    private AgentOnline selectAgent() throws UnknownOnlineAgentException, UnAvailableAgentException {
        AgentSessionService bean = BeansProvider.getBean(AgentSessionService.class);
        assert bean != null;
        Collection<AgentOnline> list = bean.getOnlineAgentList();
        if (list.isEmpty()) {
            throw new UnknownOnlineAgentException("没有在线的agent");
        }
        Collection<AgentOnline> copy = copyList(list);
        Iterator<AgentOnline> iterator = copy.iterator();
        while (iterator.hasNext()) {
            AgentOnline next = iterator.next();
            if (!next.available()) {
                iterator.remove();
            }
        }
        if (copy.isEmpty()) {
            throw new UnAvailableAgentException("无可用的agent");
        }

        return AgentSelectorFactory.getSelector(job.schedulingStrategy).select(copy);
    }

    private Collection<AgentOnline> copyList(Collection<AgentOnline> list) {
        List<AgentOnline> result = new ArrayList<>(list.size());
        result.addAll(list);
        return result;
    }

    public void checkPendingTimeout() throws TimeoutException {
        boolean after = new Date().after(pendingTimeout);
        if (after) {
            throw new TimeoutException("job(" + job.number + ")等待超时,创建时间:" + job.createTime.toString());
        }
    }

    @Override
    public void initJobStatus() {
        job.status = JobStatus.PENDING;
    }
}
